package com.jsl.action;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import weaver.file.Prop;

import java.io.File;
import java.io.FileInputStream;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 通用热更新管理器：抽离类加载、实例管理、热更新触发等通用逻辑
 * 每个模块可通过此类获取自己的实例，无需重复实现类加载逻辑
 */
public class HotSwapManager {
    private static final Logger log = LoggerFactory.getLogger(HotSwapManager.class);

    // 每个模块的唯一标识（如"project"、"user"等），用于隔离不同模块的配置和实例
    private final String moduleKey;

    // 模块专属配置（从外部传入或配置文件读取）
    private final String baseClassPath;    // 类文件根目录
    private final String basePackage;      // 基础包名
    private final List<String> excludedClasses;  // 排除的类
    private final int maxClassLoaders;     // 最大类加载器数量

    // 核心状态：类加载器、实例缓存、修改时间记录
    private volatile ClassLoader currentClassLoader;
    // 接口实例缓存
    private final Map<Class<?>, Object> interfaceInstances = new ConcurrentHashMap<>();
    // 类修改时间记录
    private final Map<String, Long> classLastModifiedMap = new ConcurrentHashMap<>();
    // 类加载器缓存
    private final List<WeakReference<ClassLoader>> classLoaders = new ArrayList<>();

    private volatile boolean initialized = false;

    /**
     * 构造方法：通过模块标识初始化配置
     * @param moduleKey 模块唯一标识（用于读取模块专属配置）
     */
    public HotSwapManager(String moduleKey) {
        this.moduleKey = moduleKey;
        // 读取模块专属配置（配置文件中用"模块名.前缀"区分，如"project.hotswap.classPath"）
        this.baseClassPath = getConfigWithDefault("hotswap.classPath", "d:/");
        this.basePackage = getConfigWithDefault("hotswap.basePackage", "hotswap." + moduleKey);
        String excludedStr = getConfigWithDefault("hotswap.excludedClasses", "");
        this.excludedClasses = parseExcludedClasses(excludedStr);
        this.maxClassLoaders = Integer.parseInt(getConfigWithDefault("hotswap.maxClassLoaders", "3"));

        // 初始化（扫描类+加载初始实例）
        init();
    }

    /**
     * 从配置文件读取模块专属配置（支持默认值）
     */
    private String getConfigWithDefault(String configKey, String defaultValue) {
        // 配置键格式：模块名.配置项（如"project.hotswap.classPath"）
        String fullKey = moduleKey + "." + configKey;
        String value = Prop.getPropValue("JslWorkflow", fullKey);
        return StringUtils.isEmpty(value) ? defaultValue : value;
    }

    /**
     * 初始化：扫描类并加载初始实例
     */
    public synchronized void init() {
        if (initialized) {
            log.info("模块[{}]已初始化，无需重复执行", moduleKey);
            return;
        }

        try {
            log.info("开始初始化模块[{}]的热更新管理器：baseClassPath={}, basePackage={}",
                    moduleKey, baseClassPath, basePackage);

            // 1. 扫描可热更新的类
            List<String> classNames = scanPackage();
            if (classNames.isEmpty()) {
                log.warn("模块[{}]未找到可热更新的类（路径：{}，包名：{}）", moduleKey, baseClassPath, basePackage);
                initialized = true;
                return;
            }
            log.info("模块[{}]发现可热更新的类：{}", moduleKey, classNames);

            // 2. 初始化类修改时间记录
            initClassLastModified(classNames);

            // 3. 初始化类加载器并加载实例
            initClassLoader();
            int successCount = loadAllClasses(classNames);
            log.info("模块[{}]初始化完成：共{}个类，成功加载{}个", moduleKey, classNames.size(), successCount);

            initialized = true;
        } catch (Exception e) {
            log.error("模块[{}]热更新管理器初始化失败", moduleKey, e);
            throw new RuntimeException("模块[" + moduleKey + "]初始化异常", e);
        }
    }

    /**
     * 获取目标接口的最新实例（核心方法：供业务Action调用）
     * @param interfaceClass 接口类（如AddProjectInterface.class）
     * @return 接口的最新实现类实例
     */
    public <T> T getInstance(Class<T> interfaceClass) {
        if (!initialized) {
            synchronized (this) {
                if (!initialized) {
                    init(); // 确保初始化完成
                }
            }
        }

        T instance = (T) interfaceInstances.get(interfaceClass);
        if (instance == null) {
            throw new IllegalStateException("模块[" + moduleKey + "]未找到接口[" + interfaceClass.getName() + "]的实现类");
        }
        return instance;
    }

    /**
     * 手动触发热更新（供外部调用，如Controller）
     * @return 更新结果信息
     */
    public Map<String, List<String>> triggerHotSwap() {
        Map<String, List<String>> result = new ConcurrentHashMap<>();
        List<String> infoList = new ArrayList<>();

        try {
            log.info("模块[{}]开始执行热更新检查...", moduleKey);

            // 1. 重新扫描类
            List<String> classNames = scanPackage();
            if (classNames.isEmpty()) {
                infoList.add("未找到可热更新的类");
                result.put("info", infoList);
                return result;
            }

            // 2. 检查变化的类
            List<String> changedClasses = checkChangedClasses(classNames);
            if (changedClasses.isEmpty()) {
                infoList.add("未检测到任何类变化，无需更新");
                result.put("info", infoList);
                return result;
            }
            log.info("模块[{}]检测到变化的类：{}", moduleKey, changedClasses);

            // 3. 重新加载并更新实例
            synchronized (this) {
                initClassLoader(); // 新建类加载器
                int successCount = loadAllClasses(classNames);
                infoList.add("变更后重新加载完成：共" + classNames.size() + "个类，成功加载" + successCount + "个");
                cleanupClassLoaders(); // 清理旧加载器
            }
        } catch (Exception e) {
            log.error("模块[{}]热更新执行异常", moduleKey, e);
            infoList.add("热更新失败：" + e.getMessage());
        }

        result.put("info", infoList);
        return result;
    }

    // -------------------------- 以下为内部辅助方法 --------------------------

    /**
     * 扫描包下的所有类（排除接口和指定类）
     */
    private List<String> scanPackage() {
        List<String> classNames = new ArrayList<>();
        String packagePath = basePackage.replace('.', File.separatorChar);
        File baseDir = new File(baseClassPath);

        if (!baseDir.exists() || !baseDir.isDirectory()) {
            log.error("模块[{}]类文件根目录不存在：{}", moduleKey, baseClassPath);
            return classNames;
        }

        File packageDir = new File(baseClassPath + packagePath);
        if (packageDir.exists() && packageDir.isDirectory()) {
            findClasses(packageDir, basePackage, classNames);
        } else {
            log.error("模块[{}]包目录不存在：{}", moduleKey, packageDir.getAbsolutePath());
        }

        classNames.removeAll(excludedClasses);
        return classNames;
    }

    /**
     * 递归查找类文件
     */
    private void findClasses(File dir, String packageName, List<String> classNames) {
        if (!dir.exists()) return;
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                findClasses(file, packageName + "." + file.getName(), classNames);
            } else if (file.getName().endsWith(".class")) {
                String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                classNames.add(className);
            }
        }
    }

    /**
     * 解析排除的类列表
     */
    private List<String> parseExcludedClasses(String excludedStr) {
        if (StringUtils.isEmpty(excludedStr)) {
            return Collections.emptyList();
        }
        return Arrays.stream(excludedStr.split(","))
                .map(String::trim)
                .filter(cls -> !cls.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 初始化类修改时间
     */
    private void initClassLastModified(List<String> classNames) {
        for (String className : classNames) {
            File classFile = getClassFile(className);
            if (classFile.exists()) {
                classLastModifiedMap.put(className, classFile.lastModified());
            }
        }
    }

    /**
     * 初始化类加载器（模块专属加载器）
     */
    private void initClassLoader() {
        currentClassLoader = new HotSwapClassLoader(moduleKey, baseClassPath, basePackage);
        synchronized (classLoaders) {
            classLoaders.removeIf(ref -> ref.get() == null);
            classLoaders.add(new WeakReference<>(currentClassLoader));
            log.info("模块[{}]新建类加载器（ID：{}），当前总数：{}",
                    moduleKey, currentClassLoader.hashCode(), classLoaders.size());
        }
    }

    /**
     * 加载所有类并更新实例缓存
     */
    private int loadAllClasses(List<String> classNames) {
        int successCount = 0;
        for (String className : classNames) {
            if (loadSingleClass(className)) {
                successCount++;
            }
        }
        return successCount;
    }

    /**
     * 加载单个类并更新实例（如果是接口实现类）
     */
    private boolean loadSingleClass(String className) {
        try {
            Class<?> aClass = currentClassLoader.loadClass(className);
            if (aClass.isInterface()) return false;

            // 遍历类实现的所有接口，匹配则更新实例缓存
            Class<?>[] interfaces = aClass.getInterfaces();
            for (Class<?> iface : interfaces) {
                // 只缓存接口的实例（避免非接口类被误缓存）
                interfaceInstances.put(iface, aClass.newInstance());
                log.info("模块[{}]类[{}]实现了接口[{}]，已更新实例",
                        moduleKey, className, iface.getName());
            }
            return true;
        } catch (Exception e) {
            log.error("模块[{}]加载类[{}]失败", moduleKey, className, e);
            return false;
        }
    }

    /**
     * 检查变化的类
     */
    private List<String> checkChangedClasses(List<String> classNames) {
        List<String> changedClasses = new ArrayList<>();
        for (String className : classNames) {
            File classFile = getClassFile(className);
            if (classFile.exists()) {
                long currentModified = classFile.lastModified();
                long lastModified = classLastModifiedMap.getOrDefault(className, 0L);
                if (currentModified != lastModified) {
                    changedClasses.add(className);
                    classLastModifiedMap.put(className, currentModified);
                }
            }
        }
        return changedClasses;
    }

    /**
     * 清理旧的类加载器
     */
    private void cleanupClassLoaders() {
        synchronized (classLoaders) {
            classLoaders.removeIf(ref -> ref.get() == null);
            int currentSize = classLoaders.size();
            if (currentSize > maxClassLoaders) {
                int removeCount = currentSize - maxClassLoaders;
                classLoaders.subList(0, removeCount).clear();
                log.info("模块[{}]清理旧类加载器：移除{}个，剩余{}个",
                        moduleKey, removeCount, classLoaders.size());
            }
        }
    }

    /**
     * 获取类文件对象
     */
    private File getClassFile(String className) {
        String classFilePath = className.replace('.', File.separatorChar) + ".class";
        return new File(baseClassPath + classFilePath);
    }

    /**
     * 模块专属类加载器（内部类，避免外部依赖）
     */
    private static class HotSwapClassLoader extends ClassLoader {
        private final String moduleKey;
        private final String classPath;
        private final String basePackage;

        public HotSwapClassLoader(String moduleKey, String classPath, String basePackage) {
            // 明确指定父类加载器为系统类加载器
            super(Thread.currentThread().getContextClassLoader());
            this.moduleKey = moduleKey;
            this.classPath = classPath;
            this.basePackage = basePackage;
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            // 只加载当前模块基础包下的类，其他类委托给父加载器
            if (name.startsWith(basePackage)) {
                synchronized (getClassLoadingLock(name)) {
                    Class<?> c = findLoadedClass(name);
                    if (c == null) {
                        c = findClass(name);
                    }
                    return c;
                }
            }
            try {
                // 其他类（如接口类）委托给系统类加载器
                return super.loadClass(name);
            } catch (ClassNotFoundException e) {
                log.error("父加载器无法加载类: {}, 错误: {}", name, e.getMessage());
                throw e; // 重新抛出，不要让系统回退到findClass
            }
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] classData = loadClassData(name);
                if (classData == null) {
                    throw new ClassNotFoundException("类文件不存在：" + name);
                }
                return defineClass(name, classData, 0, classData.length);
            } catch (Exception e) {
                throw new ClassNotFoundException("模块[" + moduleKey + "]加载类失败：" + name, e);
            }
        }

        private byte[] loadClassData(String className) throws Exception {
            String path = classPath + className.replace('.', File.separatorChar) + ".class";
            File file = new File(path);
            if (!file.exists()) {
                return null;
            }

            try (FileInputStream fis = new FileInputStream(file);
                 java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream()) {
                byte[] buffer = new byte[4096];
                int len;
                while ((len = fis.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
                return bos.toByteArray();
            }
        }
    }
}